package com.example.study.jetpack.compose

import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
 

/**
 *  created by 20300
 *   on 2022/3/10
 *   describe:https://blog.csdn.net/Mr_Tony/article/details/118876084?spm=1001.2014.3001.5502
 */
class Compose的文字 {
   /* compose中的文字
    文字对任何界面都属于核心内容,而利用jetpakc compose可以更轻松地显示或写入文字.
    Compose可以充分利用其构建块的组合,这意味着无需覆盖各种属性和方法,也无需扩展大型类,
    即可拥有特定的可组合项设计以及按照你期望的方式运行的逻辑.

    Compose提供了基础的BasicText和BasicTextField,它们是用于显示文字以及处理用户输入的主要函数.
    Compose还提供了跟高级的text和textField,它们是遵循Material Design准则的可组合项.建议在Android平台
    上使用这些构建块,因为它们的外观和样式非常适合Android用户,而且还包含可用以简化用户自定义设置的其他选项,
    无需编写大量代码

    显示文字
    显示文字的最基本方法是使用以String作为参数的Text可组合项:
    示例:
    */
   @Composable
   fun SimpleText() {
       Text("Hello World")
   }
   /* 显示资源中的文字
    建议使用字符串资源,而不是对Text值进行硬编码,因为使用字符串资源时可以与视图共享相同字符串,
    并为你的应用国际化做准备*/
   @Composable
   fun StringResourceText() {
       Text(stringResource(R.string.app_name))
   }
    /*设置文字样式
    Text可组合项有多个用于为其内容设置样式的可选参数.以下列出了适用于常见文字用例的参数.如需查看Text的
    所有参数,建议查阅Compose text 源代码
    每当设置其中任何一个参数,都会将样式应用于整个文字值.如果需要在同一行或段落中
    应用多种样式,请参阅多种内嵌样式的部分,
    */


    /*文字对齐
    通过textAlign参数,可以在Text可组合项的Surface区域设置文字对齐样式
    默认情况下,Text会根据其内容值选择自然的文字对齐方式:
    `对于从左到右书写的文字,如拉丁语,向text容器的左边缘对齐,反之向右
    */
    @Preview(showBackground = true)
    @Composable
    fun CenterText() {
        Text("Hello World", textAlign = TextAlign.Center,
            modifier = Modifier.width(150.dp))
    }
    /*处理字体
    Text有一个fontFamily参数,用于设置可组合项中使用的字体.默认情况下,系统会添加Serif,
    Sans Serif,等宽和Cursive字体系列:
    示例:
    */
    @Composable
    fun DifferentFonts() {
        Column {
            Text("Hello World", fontFamily = FontFamily.Serif)
            Text("Hello World", fontFamily = FontFamily.SansSerif)
        }
    }
    /*
    可以使用fontFamily属性来处理res/fonts文件夹中定义的自定义字体和字型
    示例:
    val firaSansFamily = FontFamily(
        Font(R.font.firasans_light, FontWeight.Light),
        Font(R.font.firasans_regular, FontWeight.Normal),
        Font(R.font.firasans_italic, FontWeight.Normal, FontStyle.Italic),
        Font(R.font.firasans_medium, FontWeight.Medium),
        Font(R.font.firasans_bold, FontWeight.Bold)
    )
    可以将此fontFamily传递给Test可组合项.由于fontFamily可以包含不同的粗细度,可以手动设置fontWeight
    来为文字选择合适的粗细度
    示例:   超链接的另一种实现方式?
    Column {
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Light)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal)
    Text(
        ..., fontFamily = firaSansFamily, fontWeight = FontWeight.Normal,
        fontStyle = FontStyle.Italic
    )
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Medium)
    Text(..., fontFamily = firaSansFamily, fontWeight = FontWeight.Bold)
}

    */

    /*文字中包含多种样式
    如需在同一Text可组合项中设置不同的样式,必须使用AnnotatedString,该字符串可食用任意注解
    样式加以注解.
    AnnotatedString是一个数据类,其中包含:
    `一个Text值
    `一个SpanStyleRange的List,等同于位置范围在文字值内的内嵌样式
    `一个ParagraphStyleRange的List,用于指定文字对齐,文字方向,行高和文字缩进样式

    TextStyle用于Text可组合项,而SpanStyle和ParagraphStyle用于AnnotatedString
    SpanStyle和ParagraphStyle之间的区别在于,ParagraphStyle可应用于整个段落,而
    SpanStyle可以在字符级别应用,一旦用ParagraphStyle标记了一部分文字,该部分就会与其余部分隔开,
    就像开头和末尾有换行符一样
    AnnotatedString有一个类型安全的构建器,以便更轻松地创建以下代码:
    示例:
    */
    @Composable
    fun MultipleStylesInText() {
        Text(
            buildAnnotatedString {
                withStyle(style = SpanStyle(color = Color.Blue)) {
                    append("H")
                }
                append("ello ")

                withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, color = Color.Red)) {
                    append("W")
                }
                append("orld")
            }
        )
    }
    @Composable
    fun paragraphStyle() {
        Text(
            buildAnnotatedString {
                withStyle(style = ParagraphStyle(lineHeight = 30.sp)) {
                    withStyle(style = SpanStyle(color = Color.Blue)) {
                        append("Hello\n")
                    }
                    withStyle(
                        style = SpanStyle(
                            fontWeight = FontWeight.Bold,
                            color = Color.Red
                        )
                    ) {
                        append("World\n")
                    }
                    append("Compose")
                }
            }
        )
    }
    /*行数上限
    如需限制Text可组合项中的可见行数,如下方式设置maxLines参数
    示例:*/
    @Composable
    fun LongText() {
        Text("hello ".repeat(50), maxLines = 2)
    }

    /*文字溢出
    在限制长文字时,可能需要指定文字溢出,这些内容只有在显示的文字被截断时才会显示,如需指定文字溢出,
    如下方式设置textOverflow参数:
    */
    @Composable
    fun OverflowedText() {
        Text("Hello Compose ".repeat(50), maxLines = 2, overflow = TextOverflow.Ellipsis)
    }

    /*用户互动
    jetPack Compose支持Text中的精细互动.文字选择现在更加灵活,并且可以跨越各种可组合项布局进行选择
    文字中的用户互动与其他可组合项布局不同.因为无法为Text可组合项地某一部分添加修饰符
    选择文字
    默认情况下,可组合项不可选择,这意味在默认情况下用户无法从你的应用中选择和复制文字.要启用文字选择,
    需要使用SelectionContainer可组合项封装文字元素
    示例:
    */
    @Composable
    fun SelectableText() {
        SelectionContainer {
            Text("This text is selectable")
        }
    }
    /*你可能想为可选择区域的特定不封停用选择功能,如果要执行此操作,你需要使用
    DisableSelection可组合项来封装不可选择的部分:
    示例:
    */
    @Composable
    fun PartiallySelectableText() {
        SelectionContainer {
            Column {
                Text("This text is selectable")
                Text("This one too")
                Text("This one as well")
                DisableSelection {
                    Text("But not this one")
                    Text("Neither this one")
                }
                Text("But again, you can select this one")
                Text("And this one too")
            }
        }
    }

    /*获取点击文字的位置
    如需监听Text文字的点击次数,你可以添加clickable修饰符.不过,如果想在text可组合项内获取点击位置,
    在对文字的不同部分执行不同操作的情况下,需要该用ClickableText
    */
    @Composable
    fun SimpleClickableText() {
        ClickableText(
            text = AnnotatedString("Click Me"),
            onClick = { offset ->
                Log.d("ClickableText", "$offset -th character is clicked.")
            }
        )
    }
    /*点击注解
    当用户点击Text可组合项时,你可能想向Text值的某一部分附加额外信息,例如向特定字词附加可在浏览器中打开的网址
    如果要执行此操作,你需要附加一个注解,用于获取一个标记(String),一个项(String)和一个文字范围作为参数.在
    AnnotatedString中,这些注解可以按照其标记或文字范围进行过滤
    示例:
    */
    @Composable
    fun AnnotatedClickableText() {
        val annotatedText = buildAnnotatedString {
            append("Click ")

            // We attach this *URL* annotation to the following content
            // until `pop()` is called
            pushStringAnnotation(tag = "URL",
                annotation = "https://developer.android.com")
            withStyle(style = SpanStyle(color = Color.Blue,
                fontWeight = FontWeight.Bold)) {
                append("here")
            }

            pop()
        }

        ClickableText(
            text = annotatedText,
            onClick = { offset ->
                // We check if there is an *URL* annotation attached to the text
                // at the clicked position
                annotatedText.getStringAnnotations(tag = "URL", start = offset,
                    end = offset)
                    .firstOrNull()?.let { annotation ->
                        // If yes, we log its value
                        Log.d("Clicked URL", annotation.item)
                    }
            }
        )
    }

    /*输入和修改文字
    TextField允许用户输入和修改文字.TextField实现分为两个级别:
    1.TextField
    是Material Design实现,建议选此实现,因为它遵循的是Material Design指南
    1)默认样式为填充
    2)outlinedTextField是轮廓样式版本
    2.BaseTextField允许用户通过硬件或软键盘编辑文字,但没有提供提示或占位符等装饰
    示例:
    */
    @Composable
    fun SimpleFilledTextFieldSample() {
        var text by remember { mutableStateOf("Hello") }

        TextField(
            value = text,
            onValueChange = { text = it },
            label = { Text("Label") }
        )
    }

    /*设置TextField样式
    TextField和BasicTextField共用许多可对它们进行自定义地常用参数.全部查看源码
    `singleLine
    `maxLines
    `textStyle
    */
    @Composable
    fun StyledTextField() {
        var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }

        TextField(
            value = value,
            onValueChange = { value = it },
            label = { Text("Enter text") },
            maxLines = 2,
            textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
            modifier = Modifier.padding(20.dp)
        )
    }

    /*如果你的设计调用Material TextField或Outline TextField,建议你使用TextField而不是BasicTextField.
    但是,在构建无需Material规范中的装饰的设计时,应使用BasicTextField
    */

    /*键盘选项
    借助TextField,可以设置键盘配置选项(例如键盘布局),或启用自动更正(如果键盘支持的话).
    如果软件键盘不符合此处提供的选项,则无法保证某些选项的可用性.
    下面列出了支持键盘选项
    `capitalization
    `autoCorrect
    `keyboardType
    `imAction
    */

    /*格式设置
    TextField允许为输入值设置视觉格式,例如将密码中的字符替换为*,或在信用卡号码中每4为插入一个连字符:
    示例;
    */
    @Composable
    fun PasswordTextField() {
        var password by rememberSaveable { mutableStateOf("") }

        TextField(
            value = password,
            onValueChange = { password = it },
            label = { Text("Enter password") },
            visualTransformation = PasswordVisualTransformation(),
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
        )
    }











}